﻿/** @file String.h
	@brief	文字列クラス定義ファイル
*/

#ifndef STRAY_STRING_STRING_H
#define STRAY_STRING_STRING_H

#include <string>
#include "../Common.h"
#include "../Container/Vector.h"
#include "../SmartPtr/UniquePtr.h"
#include "Encoding.h"
#include "Char.h"

/**
	@brief ライブラリの名前空間
*/
namespace Stray {

class StringImpl;

/** 
	@brief	文字列クラス
			実装クラスの生成にはnew(std::nothrow)を使用しているので、コンストラクタでpImple_のnewに失敗しても例外を投げない。
			生成に失敗した場合、各メソッドは動作しないで呼び出し元にもどる。
			戻り値があるものは、符号あり整数は-1、符号なし整数、bool値、ポインタを返すものは0、
			それ以外は規定のコンストラクタで生成されたオブジェクトを返す。
*/
class String
{
public:
	/**
		@brief	コンストラクタ。
	*/
	String();

	/**
		@brief	コンストラクタ。指定の文字列で初期化。(エンコードは処理系のchar型文字列にあわせる)
		@param	pString 文字列へのポインタ。
	*/
	String(const char* pString);

	/**
		@brief	コンストラクタ。指定の文字列で初期化。(Unicodeで受け取る。エンコードは処理系のwchar_t型文字列にあわせる)
		@param	pString 文字列へのポインタ。
	*/
	String(const wchar_t* pString);

	/**
		@brief	コンストラクタ。指定のエンコードの文字列で初期化。
		@param	pString 文字列へのポインタ。
		@param	encoding エンコード方法。
	*/
	String(const void* pString, Encoding encoding);

	/**
		@brief	デストラクタ
	*/
	~String();

	/**
		@brief	コピーコンストラクタ。
		@param	rhs コピー元。
	*/
	String(const String& rhs);

	/**
		@brief	代入演算子
		@param	rhs コピー元。
		@return	代入後の自分の参照。
	*/
	String& operator =(const String& rhs);

	/**
		@brief	実装クラスのインスタンスが生成されたかどうか確認。生成されていればture、失敗していればfalseを返す。
	*/
	bool isValid() const;

	/**
		@brief	指定のエンコードの文字列をセットする。
		@param	pString	セットする文字列へのポインタ。
		@param	encoding セットする文字列のエンコード。
	*/
	void setString(const void* pString, Encoding encoding);

	/**
		@brief	文字列の文字数を返す。
		@return	文字数。
	*/
	size_t length() const;

	/**
		@brief	引数で指定されたエンコード時の文字列のバイトサイズを返す。
		@param	encoding エンコード方法。
		@return	バイト数。
	*/
	size_t byteSize(Encoding encoding) const;

	/**
		@brief	char型の文字列に変換して返す。(エンコードは処理系にあわせる)
		@return	変換後の文字列へのポインタ。
	*/
	const char* toChar() const;

	/**
		@brief	wchar_t型の文字列に変換して返す。(エンコードは処理系にあわせる)
		@return	変換後の文字列へのポインタ。
	*/
	const wchar_t* toWchar() const;

	/**
		@brief	指定したエンコードのstd::stringに変換して返す。Unicodeを指定された場合、UTF-8の文字列で返す。
		@param	encoding エンコード方法
		@return	変換後のstd::string。
	*/
	std::string toString(Encoding encoding = ENC_UTF8) const;

	/**
		@brief	std::wstringに変換して返す。エンコードは処理系依存のUnicode。
		@return	変換後の文字列
	*/
	std::wstring toWstring() const;

	/**
		@brief	ゼロインデックススタートで指定された位置の文字を返す。index == 3 だったら、文字列の先頭から4番目の文字
		@param	index 指定する文字のインデックス。
		@return	文字。
	*/
	Char charAt(unsigned int index) const;

	/**
		@brief	文字列の結合。thisの文字列+rhsの文字列の順に結合される。
		@param	rhs	結合される文字列。
		@return	結合後の文字列。
	*/
	String& concat(const String &rhs);

	/**
		@brief	指定した文字が何文字目にあるか検索。最初に見つかったインデックスを返す。見つからなければ-1を返す。
		@param	c 文字
		@param	start 検索開始位置
		@return	指定の文字があるインデックス
	*/
	int indexOf(const Char& c, unsigned int start = 0) const;

	/**
		@brief	指定した文字列が何文字目から始まるか検索。最初に見つかったインデックスを返す。見つからなければ-1を返す。
		@param	str 文字列
		@param	start 検索開始位置
		@return	指定の文字列の開始インデックス
	*/
	int indexOf(const String& str, unsigned int start = 0) const;

	/**
		@brief	指定した文字が何文字目にあるか文字列の最後尾から検索。最初に見つかったインデックスを返す。見つからなければ-1を返す。
		@param	c 文字
		@param	start 検索開始位置
		@return	指定の文字があるインデックス
	*/
	int lastIndexOf(const Char& c, int start) const;

	/**
		@brief	指定した文字列が何文字目から始まるか文字列の最後尾から検索。最初に見つかったインデックスを返す。見つからなければ-1を返す。
		@param	str 文字列
		@param	start 検索開始位置
		@return	指定の文字列の開始インデックス
	*/
	int lastIndexOf(const String& str, int start) const;

	/**
		@brief	文字列の比較。同一文字列ならtrueを返す。エンコード方法の違いは無視する。
		@param	rhs 比較する文字列。
		@return	結果。
	*/
	bool equals(const String& rhs) const;

	/**
		@brief	文字列の置換。第一引数で指定した文字列があれば、その部分を第二引数で指定する文字列に変換する。
		@param	searchStr 置換元の文字列。
		@param	replaceStr 置換先の文字列。
		@return 置換後の文字列
	*/
	String& replace(const String& searchStr, const String& replaceStr);

	/**
		@brief	指定した区切り文字で文字列を分割し、Stringの配列で結果を返す。
		@param	separator 区切り文字の指定。
		@return	分割された文字列。
	*/
	Vector<String>::type split(const Char& separator) const;

	/**
		@brief	指定された区間の文字列を返す。
		@param	start 区間の開始インデックス。
		@param	end 区間の終了インデックス(このインデックスの直前までが指定区間)。
		@return	指定区間の文字列。
	*/
	String substring(unsigned int start, unsigned int end) const;

	/**
		@brief	大文字アルファベットを小文字アルファベットに変換した文字列を返す。(未実装)
	*/
	String toLowerCase() const;
	
	/**
		@brief	小文字アルファベットを大文字アルファベットに変換した文字列を返す。(未実装)
	*/
	String toUpperCase() const;
private:
	typedef Stray::UniquePtr<StringImpl>::type ImplPtr;
	ImplPtr pImpl_; //!<実装
};

/**
	@brief	Stringの比較用演算子。lhs.equals(rhs)と同等。
	@param	lhs 比較する文字
	@param	rhs	比較する文字
	@return 等しいならtrue。
*/
bool operator ==(const String& lhs, const String& rhs);

bool operator !=(const String& lhs, const String& rhs);

size_t hash_value(const String& str);

}

#endif